from typing import List, Dict, Any, Optional, Set
from langchain_core.documents import Document
from ..core.logger import logger


class HybridSearchEngine:
    """混合检索引擎，结合向量检索、关键词检索"""
    
    def __init__(self):
        # 重排序功能已从系统中移除
        self.reranker_available = False
        self.reranker = None
        logger.info("使用基本混合检索策略")
    
    def keyword_search(self, query: str, documents: List[Document], k: int = 5) -> List[Document]:
        """
        基于关键词的简单检索实现
        :param query: 查询字符串
        :param documents: 待检索的文档列表
        :param k: 返回的结果数量
        :return: 匹配的文档列表
        """
        if not documents or not query:
            return []
        
        # 提取查询中的关键词
        query_keywords = self._extract_keywords(query)
        if not query_keywords:
            return []
        
        # 对文档进行评分
        scored_docs = []
        for doc in documents:
            score = self._score_document(query_keywords, doc)
            if score > 0:
                scored_docs.append((doc, score))
        
        # 按分数排序并返回前k个结果
        scored_docs.sort(key=lambda x: x[1], reverse=True)
        return [doc for doc, score in scored_docs[:k]]
    
    def _extract_keywords(self, text: str) -> Set[str]:
        """从文本中提取关键词"""
        import re
        # 基本的关键词提取：去除停用词，保留名词和重要术语
        stop_words = {
            '的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', 
            '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这',
            'for', 'the', 'a', 'an', 'and', 'or', 'but', 'is', 'are', 'was', 'were', 'in', 'on', 'at'
        }
        
        # 提取中文字符和英文单词
        words = re.findall(r'[\u4e00-\u9fa5]{2,}|[A-Za-z]+', text.lower())
        # 过滤停用词
        keywords = {word for word in words if word not in stop_words and len(word) > 1}
        return keywords
    
    def _score_document(self, query_keywords: Set[str], doc: Document) -> float:
        """计算文档与查询关键词的匹配分数"""
        # 检查文档内容
        content = doc.page_content.lower()
        # 检查元数据中的标题和关键词（如果有）
        title = doc.metadata.get('title', '').lower()
        keywords = doc.metadata.get('keywords', [])
        
        # 计算匹配分数
        score = 0
        
        # 内容匹配（基础分数）
        for keyword in query_keywords:
            if keyword in content:
                # 计算关键词在内容中的出现频率
                freq = content.count(keyword)
                score += freq * 1.0
                
        # 标题匹配（更高权重）
        for keyword in query_keywords:
            if keyword in title:
                score += 5.0  # 标题匹配权重更高
        
        # 元数据关键词匹配
        for keyword in query_keywords:
            if any(kw.lower() == keyword for kw in keywords):
                score += 3.0  # 元数据关键词匹配权重
        
        return score
    
    def hybrid_search(self, vector_results: List[Document], keyword_results: List[Document], 
                     query: str, k: int = 5) -> List[Document]:
        """
        混合向量检索和关键词检索的结果
        :param vector_results: 向量检索结果
        :param keyword_results: 关键词检索结果
        :param query: 查询字符串
        :param k: 返回的结果数量
        :return: 混合后的文档列表
        """
        # 合并结果并去重
        combined_results = {}
        for doc in vector_results + keyword_results:
            # 使用文档内容的哈希值作为唯一标识（实际应用中可以使用更好的方法）
            doc_id = doc.metadata.get('id', hash(doc.page_content))
            combined_results[doc_id] = doc
        
        # 转换为列表
        all_results = list(combined_results.values())
        
        # 直接取前k个结果
        all_results = all_results[:k]
        
        return all_results
    
    def adaptive_search(self, query: str, vector_store, k: int = 5, filter: Optional[Dict[str, Any]] = None) -> List[Document]:
        """
        根据查询特征动态调整检索策略
        :param query: 查询字符串
        :param vector_store: 向量存储对象
        :param k: 返回的结果数量
        :param filter: 元数据过滤条件
        :return: 检索结果
        """
        # 分析查询特征
        query_length = len(query)
        query_words = query.split()
        
        # 判断查询类型
        is_complex_query = len(query_words) > 10 or \
                          any(keyword in query.lower() for keyword in 
                              ['explain', 'compare', 'analyze', 'summary', '关系', '比较', '分析'])
        
        is_long_query = query_length > 200
        
        logger.info(f"自适应检索分析 - 查询长度: {query_length}, 词数: {len(query_words)}, "
                    f"复杂查询: {'是' if is_complex_query else '否'}, 长查询: {'是' if is_long_query else '否'}")
        
        # 第一阶段：使用初始k值获取初步结果
        if filter:
            initial_results = vector_store.similarity_search_with_metadata_filter(query, filter=filter, k=k*2)
        else:
            initial_results = vector_store.similarity_search(query, k=k*2)
        
        # 使用VectorStore的自适应参数调整功能
        try:
            # 尝试调用_vector_store的_adjust_search_params方法
            adjusted_k, adjusted_overlap = vector_store._adjust_search_params(query, k, initial_results)
            logger.info(f"通过VectorStore自适应调整参数: k={adjusted_k}, overlap={adjusted_overlap}")
        except Exception as e:
            # 如果调用失败，使用默认的动态调整逻辑
            logger.warning(f"调用VectorStore自适应参数调整失败: {e}，使用内置逻辑")
            if is_complex_query or len(initial_results) < k:
                adjusted_k = min(k * 2, 20)  # 复杂查询或结果不足时需要更多结果
                logger.info(f"复杂查询或结果不足，调整k值为: {adjusted_k}")
            else:
                adjusted_k = k
            adjusted_overlap = max(int(adjusted_k * 0.15), 20)  # 重叠大小为k的15%，最少20
        
        # 第二阶段：使用调整后的参数重新检索
        if filter:
            vector_results = vector_store.similarity_search_with_metadata_filter(query, filter=filter, k=adjusted_k)
        else:
            vector_results = vector_store.similarity_search(query, k=adjusted_k)
        
        # 如果结果不足或者是复杂查询，可以执行额外的关键词检索来补充
        if len(vector_results) < adjusted_k // 2 or is_complex_query:
            # 这里简化处理，实际应用中可能需要获取更多候选文档进行关键词检索
            # 为了示例，我们使用向量检索的结果作为候选集
            keyword_results = self.keyword_search(query, vector_results, k=adjusted_k)
            
            # 混合结果
            combined_results = self.hybrid_search(vector_results, keyword_results, query, k=k)
            return combined_results
        else:
            # 直接返回向量检索结果的前k个文档
            return vector_results[:k]